<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #map {
            position: relative;
            width: 400px;
            height: 400px;
            background: #000;
        }
    </style>
</head>
<body>
<div id="map"></div>
<script>
class Map {
   constructor(el,rect = 10){
        this.el = el;
        this.rect = rect;
        this.data = [
            // {
            //     x: 10,
            //     y: 5,
            //     color: "red"
            // }
        ];
        this.rows = Math.ceil(Map.getStyle(el,"height") / rect);
        this.cells = Math.ceil(Map.getStyle(el,"width") / rect);
        Map.setStyle(el,"height",this.rows*rect);
        Map.setStyle(el,"width",this.cells*rect);
   } 
   static getStyle(el,attr){
        return parseFloat(getComputedStyle(el)[attr])
   }
   static setStyle(el,attr,val){
       el.style[attr] = val + "px";
   }
   setData(newData){
        this.data = this.data.concat(newData);
   }
   clearData(){
    this.data.length = 0;
   }
   include({x,y}){
        return !!this.data.find(item=>(item.x==x&&item.y==y));
   }
   render(){
        this.el.innerHTML =  this.data.map(item=>{
            return `<span style="position:absolute;left:${item.x*this.rect}px;top:${item.y*this.rect}px;width:${this.rect}px;height:${this.rect}px;background:${item.color};"></span>`
        }).join("");
   }
}
class Food {
    constructor(map,colors = ['red',"blue","yellow","pink"]){
        this.map = map;
        this.colors = colors;
        this.data = null;
        this.create();
    }
    create(){
        let x = Math.floor(Math.random()*this.map.cells);
        let y = Math.floor(Math.random()*this.map.rows);
        let color = this.colors[parseInt(Math.random()*this.colors.length)];
        this.data = {x,y,color};
        if(this.map.include(this.data)){
            this.create();
        }
        this.map.setData(this.data);
    }
}
class Snake {
    constructor(map){
        this.data = [
            {x: 6, y: 4, color: "green"},
            {x: 5, y: 4, color: "white"},
            {x: 4, y: 4, color: "white"},
            {x: 3, y: 4, color: "white"},
            {x: 2, y: 4, color: "white"}
        ];
        this.map = map;
        this.direction = "right";
        this.map.setData(this.data);
    }
    move(){
        let i = this.data.length-1;
        this.lastData = {
            x: this.data[i].x,
            y: this.data[i].y,
            color: this.data[i].color
        }
        /*让后边每一格走到前一格的位置上*/
        for(i; i > 0; i--){
            this.data[i].x = this.data[i-1].x;
            this.data[i].y = this.data[i-1].y;
        }

        // 根据方向移动蛇头
        switch(this.direction){
            case "left":
                this.data[0].x--;
                break;
            case "right":
                this.data[0].x++;
                break;
            case "top":
                this.data[0].y--;
                break;
            case "bottom":
                this.data[0].y++;
                break;             
        }
    }
    changeDir(dir){
        // 如果蛇本身现在在左右移动，我们只能修改让蛇上下移动
        if(this.direction === "left"||this.direction === "right"){
            if(dir==="left"||dir==="right"){
                return false; // 不能修改方向
            }
        } else {
            if(dir==="top"||dir==="bottom"){
                return false; // 不能修改方向
            }
        }
        this.direction = dir;
        return true;
        // 如果蛇正在上下移动，我们只能修改让蛇左右移动
    }
    // 吃到了食物蛇应该变大了
    eatFood(){
        this.data.push(this.lastData);
    }
}
class Game {
    constructor(el,rect,toControl = null){
        this.map = new Map(el,rect);
        this.food = new Food(this.map);
        this.snake = new Snake(this.map);
        this.map.render();
        this.timer = 0;
        this.interval = 200;
        this.toControl = toControl;
        this.keyDown = this.keyDown.bind(this);
        this.control();
    }
    // 开始游戏
    start(){
        this.move();
    }
    // 暂停游戏
    stop(){
        clearInterval(this.timer);
    }
    // 控制移动
    move(){
        this.stop();
        this.timer = setInterval(()=>{
            this.snake.move();
            this.map.clearData();
            this.map.setData(this.snake.data);
            this.map.setData(this.food.data);
            this.map.render();
        },this.interval);
    }
    //判断是否结束 
    isOver(){

    }
    // 游戏结束
    over(){

    }
    keyDown({keyCode}){
        //console.log(keyCode);
        let isDir;
        switch(keyCode){
            case 37:
                isDir = this.snake.changeDir("left");
                break;
            case 38:
                isDir = this.snake.changeDir("top");
                break;
            case 39:
                isDir = this.snake.changeDir("right");
                break;
            case 40:
                isDir = this.snake.changeDir("bottom");
                break;            
        }
        console.log(isDir);
    }
    // 控制器 
    control(){
        if(this.toControl){
            this.toControl();
            return ;
        }
        window.addEventListener("keydown",this.keyDown);
    }
    addControl(fn){
        fn.call(this);
        window.removeEventListener("keydown",this.keyDown);
    }

}
{
    let map = document.querySelector("#map");
    // let gameMap = new Map(map,10);
    // let gameFood = new Food(gameMap);
    // let gameSnake = new Snake(gameMap,gameFood);
    let game = new Game(map,10);
    // w 87 上
    // d 68 右
    // s 83 下
    // a 65 左
    game.addControl(function(){
        window.addEventListener("keydown",({keyCode})=>{
            switch(keyCode){
                case 65:
                    this.snake.changeDir("left");
                    break;
                case 87:
                    this.snake.changeDir("top");
                    break;
                case 68:
                    this.snake.changeDir("right");
                    break;
                case 83:
                    this.snake.changeDir("bottom");
                    break;            
            }
        });
    });
    document.onclick = function(){
        game.start();
    };
}
</script>
</body>
</html>